package pl.edu.mimuw.irs.core.model.petrinet;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import pl.edu.mimuw.irs.core.global.IDManager;
import pl.edu.mimuw.irs.core.model.design.exception.InternalDesignException;
import pl.edu.mimuw.irs.core.model.design.exception.InternalDesignException.DesignCause;

/**
 * Generally every element of the net. 
 * @author Jakub Rauch
 * Created on: 2009-05-07
 */
public abstract class Element implements IElement {

	private static final long serialVersionUID = 241655908565955213L;
	
	// *** Attributes

	/** Identification string of this element. It should be unique in whole net the element belongs to. The id property
	 * is generated by idManager depending on currently available names. However, the id can be set manually, but it must
	 * be ensured that new id is not existing yet in the net. Otherwise it will throw an exception. */
	private String id;
	/** Manager for {@link #id} generation. */
	private IDManager idManager;
	/** Listeners attached to this object. */
	private PropertyChangeSupport listeners;
	
	@Override
	public String getId() {
		if (id == null) setId(getIdManager().getNewId());
		return id;
	}
	public void setId(String id) {
		getIdManager().changeId(this.id, id);
		if (this.id != id)
			getListeners().firePropertyChange("id", this.id, this.id = id);
	}
	@Override
	public IDManager getIdManager() {
		return idManager;
	}
	public void setIdManager(IDManager idManager) {
		if (this.idManager == idManager) return;
		/* Remove from old manager if attached. */
		if (this.idManager == null) {
			throw new InternalDesignException(DesignCause.NET_MEMBER_WITHOUT_ID_MANAGER, this);
		} else {
			this.setId(null);
		}
		
		/* Add to new manager. */
		this.idManager = idManager;
	}
	public PropertyChangeSupport getListeners() {
		if (listeners == null) listeners = new PropertyChangeSupport(this);
		return listeners;
	}
	
	// *** Constructors
	
	/** Serialization constructor. */
	public Element() {}

	/** General constructor */ 
	public Element(IDManager idManager) {
		this.idManager = idManager;
	}
	
	/** Copying constructor. */
	public Element(Element element) {
		this.idManager = element.getIdManager();
		this.id = idManager.getPrefixedNewId(element.getId());
	}
	
	// *** Methods
	
	@Override
	public void addPropertyChangeListener(PropertyChangeListener listener) {
		getListeners().addPropertyChangeListener(listener);
	}

	@Override
	public void addPropertyChangeListener(String property, PropertyChangeListener listener) {
		getListeners().addPropertyChangeListener(property, listener);
	}
	
	@Override
	public void removePropertyChangeListener(PropertyChangeListener listener) {
		getListeners().removePropertyChangeListener(listener);
	}
	
	@Override
	public void removePropertyChangeListener(String property, PropertyChangeListener listener) {
		getListeners().removePropertyChangeListener(property, listener);
	}

	@Override
	protected void finalize() throws Throwable {
		getIdManager().remove(getId());
		super.finalize();
	}

	@Override
	public String toString() {
		return getId();
	}
}
